//
//  UIButton+ALExtension.swift
//  ALCore
//
//  Created by IdeaBank on 2023/12/18.
//

import UIKit

public extension UIButton {

    /// 设置背景色
    func setBackgroundColor(_ color: UIColor, forState: UIControl.State) {
        UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
        UIGraphicsGetCurrentContext()?.setFillColor(color.cgColor)
        UIGraphicsGetCurrentContext()?.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
        let colorImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        setBackgroundImage(colorImage, for: forState)
    }
}

public extension UIButton {


//    AmassingUI
//
//    MALogger
//
//    PKDebugger
//
//    PKLogger
    /// 判断活动指示器是否正在显示中
    var isShowingIndicator: Bool {
        objc_getAssociatedObject(self, &UIButtonAssociatedIndicatorShowingKey) as? Bool ?? false
    }

    /// 显示活动指示器 (显示时将置空标题图片，指示器消失则恢复)
    ///
    /// - Parameters:
    ///   - style: 指示器样式
    ///   - color: 颜色
    ///   - cleared: 是否清除背景色，默认false
    func showIndicator(style: UIActivityIndicatorView.Style, color: UIColor? = .white, cleared: Bool = false) {
        guard !isShowingIndicator else { return }
        if !translatesAutoresizingMaskIntoConstraints {
            superview?.layoutIfNeeded()
        }

        isUserInteractionEnabled = false

        func setAssociated(_ key: UnsafeRawPointer, _ value: Any?) {
            objc_setAssociatedObject(self, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }

        if let bgColor = backgroundColor, cleared {
            setAssociated(&UIButtonAssociatedIndicatorBgColorKey, bgColor)
            backgroundColor = .clear
        }

        if let title = title(for: .normal) {
            setAssociated(&UIButtonAssociatedNormalTitleKey, title)
            setTitle("", for: .normal)
        }

        if let image = image(for: .normal) {
            setAssociated(&UIButtonAssociatedNormalImageKey, image)
            setImage(nil, for: .normal)
        }

        let indicator = UIActivityIndicatorView(style: style)
        indicator.color = color
        indicator.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
        indicator.center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
        indicator.startAnimating()
        addSubview(indicator)
        setAssociated(&UIButtonAssociatedIndicatorShowingKey, true)
        setAssociated(&UIButtonAssociatedIndicatorViewKey, indicator)
    }

    /// 显示活动指示器并自定义文本
    func showIndicatorText(_ text: String? = nil, style: UIActivityIndicatorView.Style, color: UIColor? = .white) {
        guard !isShowingIndicator else { return }
        if !translatesAutoresizingMaskIntoConstraints {
            superview?.layoutIfNeeded()
        }

        isUserInteractionEnabled = false

        func setAssociated(_ key: UnsafeRawPointer, _ value: Any?) {
            objc_setAssociatedObject(self, key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }

        let indicator = UIActivityIndicatorView.init(style: style)
        indicator.color = color
        indicator.startAnimating()
        addSubview(indicator)
        setAssociated(&UIButtonAssociatedIndicatorShowingKey, true)
        setAssociated(&UIButtonAssociatedIndicatorViewKey, indicator)

        let title = title(for: .normal) ?? ""
        setAssociated(&UIButtonAssociatedNormalTitleKey, title)
        setAssociated(&UIButtonAssociatedTitleEdgeInsetsKey, titleEdgeInsets)
        setTitle(text, for: .normal)
        let size = titleLabel!.sizeThatFits(bounds.size)
        let padding = (bounds.size.width - size.width) / 2, spacing: CGFloat = 10.0;
        let offset = (bounds.width - indicator.bounds.width - size.width - spacing) / 2
        indicator.center = CGPoint(x: offset + indicator.bounds.width / 2, y: bounds.height / 2)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: padding, bottom: 0, right: -padding + offset * 2)

        if let image = image(for: .normal) {
            setAssociated(&UIButtonAssociatedNormalImageKey, image)
            setImage(nil, for: .normal)
        }
    }

    /// 隐藏指示器
    func hideIndicator() {
        guard isShowingIndicator else { return }

        if let indicator = objc_getAssociatedObject(self, &UIButtonAssociatedIndicatorViewKey) as? UIActivityIndicatorView {
            indicator.stopAnimating()
            indicator.removeFromSuperview()
        }

        if let bgColor = objc_getAssociatedObject(self, &UIButtonAssociatedIndicatorBgColorKey) {
            backgroundColor = bgColor as? UIColor
        }

        if let title = objc_getAssociatedObject(self, &UIButtonAssociatedNormalTitleKey) {
            setTitle(title as? String, for: .normal)
        }

        if let image = objc_getAssociatedObject(self, &UIButtonAssociatedNormalImageKey) {
            setImage(image as? UIImage, for: .normal)
        }

        if let titleInsets = objc_getAssociatedObject(self, &UIButtonAssociatedTitleEdgeInsetsKey) {
            titleEdgeInsets = titleInsets as? UIEdgeInsets ?? UIEdgeInsets.zero
        }

        if let imageInsets = objc_getAssociatedObject(self, &UIButtonAssociatedImageEdgeInsetsKey) {
            imageEdgeInsets = imageInsets as? UIEdgeInsets ?? UIEdgeInsets.zero
        }

        isUserInteractionEnabled = true
        objc_setAssociatedObject(self, &UIButtonAssociatedIndicatorShowingKey, false, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

        func nilAssociated(_ key: UnsafeRawPointer) {
            objc_setAssociatedObject(self, key, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }

        nilAssociated(&UIButtonAssociatedIndicatorBgColorKey)
        nilAssociated(&UIButtonAssociatedNormalTitleKey)
        nilAssociated(&UIButtonAssociatedNormalImageKey)
        nilAssociated(&UIButtonAssociatedTitleEdgeInsetsKey)
        nilAssociated(&UIButtonAssociatedImageEdgeInsetsKey)
    }
}

private var UIButtonAssociatedIndicatorShowingKey: Void?
private var UIButtonAssociatedIndicatorViewKey: Void?
private var UIButtonAssociatedIndicatorBgColorKey: Void?
private var UIButtonAssociatedNormalTitleKey: Void?
private var UIButtonAssociatedNormalImageKey: Void?
private var UIButtonAssociatedTitleEdgeInsetsKey: Void?
private var UIButtonAssociatedImageEdgeInsetsKey: Void?


extension UIButton {

    /// 按钮图片位置类型
    public enum ImagePosition: Int {
        case top
        case left
        case bottom
        case right
    }
}

//MARK: - 链式属性函数
extension UIButton {

    /// 按钮文字 状态默认 normal
    /// - Parameters:
    ///   - title: 文案
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func title(_ title: String?, _ state: UIControl.State = .normal) -> Self {
        setTitle(title, for: state)
        return self
    }

    /// 按钮文字
    /// - Parameters:
    ///   - title: 文案
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func title(_ title: String?, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setTitle(title, for: state1)
        setTitle(title, for: state2)
        return self
    }

    /// 按钮富文本 状态默认 normal
    /// - Parameters:
    ///   - title: 文案
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func title(_ title: NSAttributedString?, _ state: UIControl.State = .normal) -> Self {
        setAttributedTitle(title, for: state)
        return self
    }

    /// 按钮富文本
    /// - Parameters:
    ///   - title: 文案
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func title(_ title: NSAttributedString?, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setAttributedTitle(title, for: state1)
        setAttributedTitle(title, for: state2)
        return self
    }

    /// 按钮字体
    /// - Parameter font: 字体
    /// - Returns: 自身
    @discardableResult
    public func font(_ font: UIFont) -> Self {
        titleLabel?.font = font
        return self
    }

    /// 按钮字体 默认常规
    /// - Parameters:
    ///   - fontSize: 字体大小
    ///   - style: 字体样式
    /// - Returns: 自身
    @discardableResult
    public func font(_ fontSize: CGFloat, _ style: UIFont.FontStyle = .normal) -> Self {
        titleLabel?.font = UIFont.fontSizeAdapter(fontSize, style)
        return self
    }

    /// 按钮文字颜色 状态默认 normal
    /// - Parameters:
    ///   - color: 文案颜色
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func titleColor(_ color: UIColor, _ state: UIControl.State = .normal) -> Self {
        setTitleColor(color, for: state)
        return self
    }

    /// 按钮文字颜色
    /// - Parameters:
    ///   - color: 文案颜色
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func titleColor(_ color: UIColor, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setTitleColor(color, for: state1)
        setTitleColor(color, for: state2)
        return self
    }

    /// 按钮文字阴影色 状态默认 normal
    /// - Parameters:
    ///   - color: 阴影色
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func shadowColor(_ color: UIColor, _ state: UIControl.State = .normal) -> Self {
        setTitleShadowColor(color, for: state)
        return self
    }

    /// 按钮文字阴影色
    /// - Parameters:
    ///   - color: 阴影色
    ///   - state2: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func shadowColor(_ color: UIColor, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setTitleShadowColor(color, for: state1)
        setTitleShadowColor(color, for: state2)
        return self
    }

    /// 按钮图片 状态默认 normal
    /// - Parameters:
    ///   - image: 图片
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func image(_ image: UIImage?, _ state: UIControl.State = .normal) -> Self {
        setImage(image, for: state)
        return self
    }

    /// 按钮图片
    /// - Parameters:
    ///   - image: 图片
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func image(_ image: UIImage?, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setImage(image, for: state1)
        setImage(image, for: state2)
        return self
    }

    /// 按钮背景色 状态默认 normal
    /// - Parameters:
    ///   - color: 背景色
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func backColor(_ color: UIColor, _ state: UIControl.State = .normal) -> Self {
        setBackgroundImage(UIImage.AL.image(color: color), for: state)
        return self
    }

    /// 按钮背景色
    /// - Parameters:
    ///   - color: 背景色
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func backColor(_ color: UIColor, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setBackgroundImage(UIImage.AL.image(color: color), for: state1)
        setBackgroundImage(UIImage.AL.image(color: color), for: state2)
        return self
    }

    /// 按钮背景图片 状态默认 normal
    /// - Parameters:
    ///   - image: 图片
    ///   - state: 状态
    /// - Returns: 自身
    @discardableResult
    public func backImage(_ image: UIImage?, _ state: UIControl.State = .normal) -> Self {
        setBackgroundImage(image, for: state)
        return self
    }

    /// 按钮背景图片
    /// - Parameters:
    ///   - image: 图片
    ///   - state1: 状态 1
    ///   - state2: 状态 2
    /// - Returns: 自身
    @discardableResult
    public func backImage(_ image: UIImage?, _ state1: UIControl.State, _ state2: UIControl.State) -> Self {
        setBackgroundImage(image, for: state1)
        setBackgroundImage(image, for: state2)
        return self
    }

    /// 按钮内容内边距
    /// - Parameters:
    ///   - edge: 边距
    /// - Returns: 自身
    @discardableResult
    public func contentEdgeInsets(_ edge: UIEdgeInsets = .zero) -> Self {
        contentEdgeInsets = edge
        return self
    }

    /// 按钮文字内边距
    /// - Parameters:
    ///   - edge: 边距
    /// - Returns: 自身
    @discardableResult
    public func titleEdgeInsets(_ edge: UIEdgeInsets = .zero) -> Self {
        titleEdgeInsets = edge
        return self
    }

    /// 按钮文字内边距
    /// - Parameters:
    ///   - top: 顶部边距
    ///   - left: 左边边距
    ///   - bottom: 底部边距
    ///   - right: 右边边距
    /// - Returns: 自身
    @discardableResult
    public func titleEdgeInsets(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> Self {
        titleEdgeInsets = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
        return self
    }

    /// 按钮图片内边距
    /// - Parameters:
    ///   - edge: 边距
    /// - Returns: 自身
    @discardableResult
    public func imageEdgeInsets(_ edge: UIEdgeInsets = .zero) -> Self {
        imageEdgeInsets = edge
        return self
    }

    /// 按钮图片内边距
    /// - Parameters:
    ///   - top: 顶部边距
    ///   - left: 左边边距
    ///   - bottom: 底部边距
    ///   - right: 右边边距
    /// - Returns: 自身
    @discardableResult
    public func imageEdgeInsets(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) -> Self {
        imageEdgeInsets = UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
        return self
    }

    /// 按钮高亮状态下图片是否会变暗 默认 true
    /// - Parameters:
    ///   - flag: 是否变暗
    /// - Returns: 自身
    @discardableResult
    public func adjustsImageWhenHighlighted(_ flag: Bool = true) -> Self {
        adjustsImageWhenHighlighted = flag
        return self
    }

    /// 按钮失效状态下图片是否会变亮 默认 true
    /// - Parameters:
    ///   - flag: 是否变暗
    /// - Returns: 自身
    @discardableResult
    public func adjustsImageWhenDisabled(_ flag: Bool = true) -> Self {
        adjustsImageWhenDisabled = flag
        return self
    }

    /// 图片&文字的布局 默认水平 图片在左文字在右 图片、文字间隔 5pt
    /// - Parameters:
    ///   - position: 按钮布局方式
    ///   - space: 图片、文字间隔 默认 5pt
    /// - Returns: 自身
    @discardableResult
    public func imagePosition(_ position: UIButton.ImagePosition = .left, space: CGFloat = 5) -> Self {
        buttonImagePosition(position, space: space)
        return self
    }
}

//MARK: - 常见功能
extension UIButton {

    /// 创建按钮 类型默认 .custom
    /// - Parameter type: 按钮类型 默认 .custom
    /// - Returns: 按钮实例
    public static func createButton(_ type: UIButton.ButtonType = .custom) -> UIButton {
        return UIButton(type: type)
    }

    /// 按钮图片和文字的布局 默认水平布局 图片在左文字在右 图片和文字间隔 5pt
    /// - Parameters:
    ///   - position: 按钮布局方式  默认水平 图片在左文字在右
    ///   - space: 图片和文字间隔 默认 5pt
    public func buttonImagePosition(_ position: UIButton.ImagePosition = .left, space: CGFloat = 5) {
        switch position {
        case .top: layoutPosition((false, false, 0), (true, true, space))
        case .left: layoutPosition((true, true, space), (false, false, 0))
        case .bottom: layoutPosition((false, false, 0), (true, false, space))
        case .right: layoutPosition((true, false, space), (false, false, 0))
        }
    }

    /// 按钮图片和文字的布局 默认水平布局 图片在左文字在右 图片和文字间隔 5pt
    /// - Parameters:
    ///   - horizontal: 水平配置
    ///   1. 参数 flag(表示是否水平布局) isLeft(图片是否在左边) space(图片和文字的间隔)
    ///   - vertical: 垂直配置
    ///   1. 1. 参数 flag(表示是否垂直布局) isTop(图片是否在上边) space(图片和文字的间隔)
    private func layoutPosition(
        _ horizontal: (flag: Bool, isLeft: Bool, space: CGFloat) = (true, true, 5),
        _ vertical: (flag: Bool, isTop: Bool, space: CGFloat) = (false, false, 0)
    ) {
        assert((horizontal.flag && !vertical.flag) || !horizontal.flag && vertical.flag, "布局设置错误, 请正确配置")
        /// 水平布局
        if horizontal.flag {
            let hSpace = horizontal.space * 0.5

            imageEdgeInsets(UIEdgeInsets(top: 0, left: -hSpace, bottom: 0, right: hSpace))
                .titleEdgeInsets(UIEdgeInsets(top: 0, left: hSpace, bottom: 0, right: -hSpace))
            if !horizontal.isLeft {
                transform = CGAffineTransform(scaleX: -1, y: 1)
                imageView?.transform  = CGAffineTransform(scaleX: -1, y: 1)
                titleLabel?.transform = CGAffineTransform(scaleX: -1, y: 1)
            }

            contentEdgeInsets(UIEdgeInsets(top: 0, left: hSpace, bottom: 0, right: hSpace))
        }
        /// 垂直布局
        if vertical.flag {
            guard let imgSize = imageView?.image?.size,
                  let text = titleLabel?.text,
                  let font = titleLabel?.font
                else { return }
            let titleSize     = NSString(string:text).size(withAttributes:[.font:font])
            let imgVOffset    = (titleSize.height + vertical.space) * 0.5
            let titleVOffset  = (imgSize.height + vertical.space) * 0.5
            let imgHOffset    = (titleSize.width) * 0.5
            let titleHOffset  = (imgSize.width) * 0.5
            let flag: CGFloat = vertical.isTop ? 1 : -1


            imageEdgeInsets(UIEdgeInsets(top: -imgVOffset * flag, left: imgHOffset, bottom: imgVOffset * flag, right: -imgHOffset))
                .titleEdgeInsets(UIEdgeInsets(top: titleVOffset * flag, left: -titleHOffset, bottom:-titleVOffset * flag, right: titleHOffset))

            let offset = (min(imgSize.height, titleSize.height) + vertical.space) * 0.5
            contentEdgeInsets(UIEdgeInsets(top: offset, left: 0, bottom: offset, right: 0))
        }
    }
}
